import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

//import flooding_prediction;

public class flooding_main {

	public static final int[] IowaIds = {3941, 3978};
	
	public static ArrayList<PWC> floodsPCs() {
		ArrayList<PWC> floods = new ArrayList<PWC>();
		Calendar basedate = flooding_prediction.Base_Date;
		for (int i =0; i <  flooding_prediction.floodingStartDates.length;i++ ) {
			int[] start_ymd = flooding_prediction.floodingStartDates[i];
			int[] end_ymd = flooding_prediction.floodingEndDates[i];
			
			Calendar startdate = new GregorianCalendar(start_ymd[0], start_ymd[1]-1, start_ymd[2]);
			Calendar edndate = new GregorianCalendar(end_ymd[0], end_ymd[1]-1, end_ymd[2]);
			long start=1+ (startdate.getTimeInMillis() - basedate.getTimeInMillis()) / (1000 * 60 * 60 * 24);
			long end=1+ (edndate.getTimeInMillis() - basedate.getTimeInMillis()) / (1000 * 60 * 60 * 24);
			PWC flood = new PWC(basedate, (int)start, (int) end, 0);
			floods.add(flood);
		}
		
		PWC.SortPWCbyStartDate(floods);
		return floods;
	}
	
	public static ArrayList<PWC> labelPCorEPC(ArrayList<PWC> clusters, int minidays, double epcthreshold) {
		ArrayList<PWC> newclusters = new ArrayList<PWC>();
		for (PWC cluster : clusters) {
			int length = cluster.getlength();
			if (length >= minidays ) {
				if (cluster.average >= epcthreshold) {
					cluster.classlabel = "EPC";
				} else {
					cluster.classlabel = "PC";
				}
				newclusters.add(cluster);
				for (int i=1;i<=(length-minidays);i++) {
					PWC sub = PWC.subPC(cluster, i, length-1);
					if (sub != null) {
						if (sub.average >= epcthreshold) {
							sub.classlabel ="EPC";
						} else {
							sub.classlabel ="PC";
						}
						if (sub.getlength() >= minidays) {
							newclusters.add(sub);}
					} else {
						System.out.println("Sub PWC error~");
					}
				}
			}
		}
		
		PWC.SortPWCbyStartDate(newclusters);
		return newclusters;
	}
	
	public static double[][] Alllocpwdata =null;
	
	public static double[][] getAlllocpwdata() throws IOException {
		String[] featureFiles = DataLoader.featureFiles;
		int PW = DataLoader.PW;
		int total_locs = flooding_prediction.totalSampleLocations;
		
		if ( Alllocpwdata == null) {
			double[][] alllocpwData = DataLoader.loadingData(featureFiles[PW], flooding_prediction.delimit, 
				total_locs, (int)flooding_prediction.Data_start_day, (int)flooding_prediction.Data_end_day);
			return alllocpwData;
		} else {
			return Alllocpwdata;
		}
		
	}
	
	public static void creatlocallocationfile(ArrayList<PWC> PCs, int back, String filename) throws IOException {	
		System.out.println("Loading PW data....");
		double[][] alllocpwData = getAlllocpwdata();
		
		double pwclowbound =0;
		double pwcpcbound =0;
		double pwcepcbound =0;
		
		int locid = 0;
		int supports;
		int totaldays;
		double confidences;
		ArrayList<PWLocation> allloc = new ArrayList<PWLocation>();
		for (double[] pwData:alllocpwData ) {
			pwclowbound = StdStats.percentile(pwData,flooding_prediction.lowPercentile);
			pwcpcbound = StdStats.percentile(pwData,flooding_prediction.PCPercentile);
			pwcepcbound = StdStats.percentile(pwData,flooding_prediction.EPCPercentile);
			//System.out.println(String.format("PWC location: %d; low: %.5f ; PC: %.5f; EPC: %.5f", locid, pwclowbound,pwcpcbound,pwcepcbound));
			ArrayList<PWC> pwcs = PWC.FindPWCs(flooding_prediction.Base_Date, pwData
					, pwclowbound, pwcpcbound, flooding_prediction.maxNonePCDays, flooding_prediction.minPCDays);
			pwcs = PWC.PWCRangeByAverage(pwcs, pwclowbound, Double.MAX_VALUE, "PWC");
			//System.out.println(String.format("PWC location: %d; number of PWCs: %d", locid, pwcs.size()));
			totaldays = PWC.totaldays(pwcs);
			supports = PWC.totaloverlapdays(PCs, pwcs, back);
			if (totaldays > 0) {
				confidences = (1.0*supports)/(1.0*totaldays);
			} else {
				confidences = 0;
			}
			allloc.add(new PWLocation(locid, supports, totaldays,confidences) );
			locid++;
		}
		
		PWLocation.StoreLocDataCSV(allloc, filename);	
	}
	
	public static void creatgloballocationfile(ArrayList<PWC> PCs, int back, String filename) throws IOException {
		System.out.println("Loading PW data....");
		double[][] alllocpwData = getAlllocpwdata();
				
		double pwclowbound = StdStats.percentile(alllocpwData,flooding_prediction.lowPercentile);
		double pwcpcbound = StdStats.percentile(alllocpwData,flooding_prediction.PCPercentile);
		double pwcepcbound = StdStats.percentile(alllocpwData,flooding_prediction.EPCPercentile);
		
		int locid = 0;
		int supports;
		int totaldays;
		double confidences;
		ArrayList<PWLocation> allloc = new ArrayList<PWLocation>();
		for (double[] pwData:alllocpwData ) {
			//System.out.println(String.format("PWC location: %d; low: %.5f ; PC: %.5f; EPC: %.5f", locid, pwclowbound,pwcpcbound,pwcepcbound));
			ArrayList<PWC> pwcs = PWC.FindPWCs(flooding_prediction.Base_Date, pwData
					, pwclowbound, pwcpcbound, flooding_prediction.maxNonePCDays, flooding_prediction.minPCDays);
			pwcs = PWC.PWCRangeByAverage(pwcs, pwclowbound, Double.MAX_VALUE, "PWC");
			//System.out.println(String.format("PWC location: %d; number of PWCs: %d", locid, pwcs.size()));
			totaldays = PWC.totaldays(pwcs);
			supports = PWC.totaloverlapdays(PCs, pwcs, back);
			if (totaldays > 0) {
				confidences = (1.0*supports)/(1.0*totaldays);
			} else {
				confidences = 0;
			}
			allloc.add(new PWLocation(locid, supports, totaldays,confidences) );
			locid++;
		}
		
		PWLocation.StoreLocDataCSV(allloc, filename);	
	}
	
	public static void creatIowalocationfile(ArrayList<PWC> PCs, int back, String filename) throws IOException {
		System.out.println("Loading PW data....");
		double[][] alllocpwData = getAlllocpwdata();
		double[][] IowalocpwData = new double[IowaIds.length][alllocpwData[0].length];
		
		for (int locindex = 0; locindex< IowaIds.length; locindex++ ) {
			IowalocpwData[locindex] = alllocpwData[IowaIds[locindex]];
		}
		
		double pwclowbound = StdStats.percentile(IowalocpwData,flooding_prediction.lowPercentile);
		double pwcpcbound = StdStats.percentile(IowalocpwData,flooding_prediction.PCPercentile);
		double pwcepcbound = StdStats.percentile(IowalocpwData,flooding_prediction.EPCPercentile);
		
		int locid = 0;
		int supports;
		int totaldays;
		double confidences;
		ArrayList<PWLocation> allloc = new ArrayList<PWLocation>();
		for (double[] pwData:alllocpwData ) {
			//System.out.println(String.format("PWC location: %d; low: %.5f ; PC: %.5f; EPC: %.5f", locid, pwclowbound,pwcpcbound,pwcepcbound));
			ArrayList<PWC> pwcs = PWC.FindPWCs(flooding_prediction.Base_Date, pwData
					, pwclowbound, pwcpcbound, flooding_prediction.maxNonePCDays, flooding_prediction.minPCDays);
			pwcs = PWC.PWCRangeByAverage(pwcs, pwclowbound, Double.MAX_VALUE, "PWC");
			//System.out.println(String.format("PWC location: %d; number of PWCs: %d", locid, pwcs.size()));
			totaldays = PWC.totaldays(pwcs);
			supports = PWC.totaloverlapdays(PCs, pwcs, back);
			if (totaldays > 0) {
				confidences = (1.0*supports)/(1.0*totaldays);
			} else {
				confidences = 0;
			}
			allloc.add(new PWLocation(locid, supports, totaldays,confidences) );
			locid++;
		}
		
		PWLocation.StoreLocDataCSV(allloc, filename);	
	}
	
	public static void originalEPC(int percentileused, int back) throws Exception {
		flooding_prediction.maxNonePCDays = 1;
		flooding_prediction.minPCDays = 5;
		flooding_prediction.maxPCDays = 36;
		flooding_prediction.lowPercentile = 0.3;
		flooding_prediction.PCPercentile = 0.94;
		flooding_prediction.EPCPercentile = 0.99;
		flooding_prediction.PercentileUsed = percentileused; //{0:"local", 1:"Iowa", 2: "global"};
		
		int[] support = {1300,800,800};
		double support_percentile = 0.8;
		double[] confidence = {0.27,0.27,0.27};
		double confidence_percentile = 0.8;
		int backdays = 6;
		//int back = 5;
		double lowbound =0;
		double pcbound =0;
		double epcbound =0;
		boolean getsupport = true;
		
		flooding_prediction.setupTime(1980, 2010, 3, 10);
		System.out.println("Loading Iowa precipitation data~");
		flooding_prediction.loadIowaPWs();
		System.out.println("Loading Iowa precipitation percentiles data~");
		flooding_prediction.getIowaPWPercentiles();
		lowbound = StdStats.percentile(flooding_prediction.IowaPWs,flooding_prediction.lowPercentile);
		pcbound = StdStats.percentile(flooding_prediction.IowaPWs,flooding_prediction.PCPercentile);
		epcbound = StdStats.percentile(flooding_prediction.IowaPWs,flooding_prediction.EPCPercentile);

		System.out.println(String.format("low: %.8f ; PC: %.8f; EPC: %.8f", lowbound,pcbound,epcbound));
		System.out.println("Searching PCs~");
		ArrayList<PWC> PEPCs = new ArrayList<PWC>();
		ArrayList<PWC> floods = floodsPCs();
		PWC.StorePCData(floods,"./data/floods.txt");
		ArrayList<PWC> clusters = PWC.FindPWCs(flooding_prediction.Base_Date, flooding_prediction.IowaPWs
				, lowbound, pcbound, flooding_prediction.maxNonePCDays, flooding_prediction.minPCDays);
		System.out.println("There are total "+ clusters.size() +" blocks");
		PWC.StorePCData(clusters,"./data/blocks.txt");
		
		ArrayList<PWC> lowdays = PWC.findlowdays(flooding_prediction.Base_Date,flooding_prediction.IowaPWs, lowbound,"PC");
		System.out.println(String.format("There are total %d days <= %.8f", lowdays.size(), lowbound ));
		
		clusters = labelPCorEPC(clusters, flooding_prediction.minPCDays, pcbound);
		System.out.println("There are total "+ clusters.size() +" Clusters");
		PWC.StorePCData(clusters,"./data/Clusters.txt");
		
		PEPCs = flooding_prediction.getPEPCs(clusters);
		PWC.StorePCData(PEPCs,"./data/PEPCs.txt");
		System.out.println("There are total "+ PEPCs.size() +" PEPCs");
		
		ArrayList<PWC> EPCs = PWC.PWCRangeByAverage(clusters, pcbound, Double.MAX_VALUE, "EPC");
		PWC.StorePCData(EPCs,"./data/EPCs.txt");
		System.out.println("There are total "+ EPCs.size() +" EPCs, each of which's avg >= "+ pcbound );
		
//		ArrayList<PWC> PCs = PWC.PWCRangeByAverage(clusters, -1, pcbound, "PC");
//		PWC.StorePCData(PCs,"./data/PCs.txt");
//		System.out.println("There are total "+ PCs.size() +" PCs, each of which's avg < "+ pcbound );
		ArrayList<PWC> PCs = PWC.findnotEPCdays(flooding_prediction.Base_Date,flooding_prediction.IowaPWs,EPCs,"PC");
		PWC.StorePCData(PCs,"./data/PCs.txt");
		System.out.println("There are total "+ PCs.size() +" PCs" );
		
		ArrayList<PWC> notcovered = PWC.coverage(floods, EPCs, 0);
		PWC.StorePCData(notcovered,"./data/notcover.txt");
		System.out.println("There are total "+ notcovered.size() +" not covered floods");
		String alllocfilename ="";
		String selectedlocfilename ="";
		String wekafilename ="";

		if (flooding_prediction.PercentileUsed == 0) {
			alllocfilename = String.format("./Loccsvdata/All_local_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			selectedlocfilename = String.format("./Loccsvdata/sel_local_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			wekafilename = String.format("local/local_%.2f_%.2f_%d.arff",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			if (getsupport) {
				creatlocallocationfile(EPCs,back,alllocfilename);
				System.out.println("Saving all location support to "+ alllocfilename );
			}
		} else if (flooding_prediction.PercentileUsed == 1) {
			alllocfilename = String.format("./Loccsvdata/All_Iowa_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			selectedlocfilename = String.format("./Loccsvdata/sel_Iowa_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			wekafilename = String.format("Iowa/Iowa_%.2f_%.2f_%d.arff",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			if (getsupport) {
				creatIowalocationfile(EPCs,back,alllocfilename);
				System.out.println("Saving all location support to "+ alllocfilename );
			}
		} else if (flooding_prediction.PercentileUsed == 2) {
			alllocfilename = String.format("./Loccsvdata/All_global_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			selectedlocfilename = String.format("./Loccsvdata/sel_global_%.2f_%.2f_%d.csv",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			wekafilename = String.format("global/global_%.2f_%.2f_%d.arff",
					flooding_prediction.lowPercentile, flooding_prediction.PCPercentile, back);
			if (getsupport) {
				creatgloballocationfile(EPCs,back,alllocfilename);
				System.out.println("Saving all location support to "+ alllocfilename );
			}
		}

		System.out.println("Loading all location support from "+ alllocfilename);
		ArrayList<PWLocation> allloc = PWLocation.LoadLocData(alllocfilename, ",");
		support[percentileused] = PWLocation.supportpercentile(allloc, support_percentile);
		//confidence[percentileused] =  PWLocation.confidencepercentile(allloc, confidence_percentile);
		confidence[percentileused] =  PWLocation.AverageConf(allloc);
		
		System.out.println(String.format("Filtering location by support >=%d and confidence>=%.7f"
				,support[percentileused],confidence[percentileused]));
		ArrayList<PWLocation> loclist = PWLocation.LOCRangeByConfidence(allloc, confidence[percentileused], Double.MAX_VALUE);
		loclist = PWLocation.TopNBySupport(loclist, 500);
		System.out.println(String.format("Thare are total %d locations.",loclist.size()));
		PWLocation.StoreLocDataCSV(loclist, selectedlocfilename);
		System.out.println("Saved selected location to "+ selectedlocfilename);
		
//		PWC.SortPWCbyStartDate(clusters);
//		PWC.SortPWCbyStartDate(PCs);
//		for (PWC cluster:clusters) {
//			if (PCs.size() ==0) {
//				cluster.classlabel = "PC";
//			} else {
//				for (int index =0; index < PCs.size(); index++) {
//					if (cluster.start_date == PCs.get(index).start_date) {
//						cluster.classlabel = "EPC";
//						PCs.remove(index);
//						break;
//					} else {
//						cluster.classlabel = "PC";
//					}
//				}
//			}
//		}
		EPCs = PWC.RandomSelection(EPCs, 500, 1);
		PCs = PWC.RandomSelection(PCs, EPCs.size(), 1);
		
		clusters=EPCs;
		for (PWC pc:PCs) {
			clusters.add(pc);
		}
		
		String[] labels= PWC.all_labels(clusters);
		System.out.print("The class lables are: ");
		for (String label:labels) {
			System.out.print(label+",");
		}
		
		System.out.println("");
		PWC.SortPWCbyStartDate(clusters);
		flooding_prediction.createWekaFile(clusters, loclist, backdays, back, labels, wekafilename);
	}
	
	public static void main(String[] args) throws Exception {
		for (int back =0; back<=0; back++) {
			for (int percentileused =0; percentileused<=2; percentileused++) {
				originalEPC(percentileused,back);
			}
		}
	}

}
